<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>属性名的遍历</title>
  </head>
  <body>
    <script>
      //Symbol作为属性名，遍历对象的时候,该属性不会出现在 for...in 、for...of循环中，
      // 也不会被Object.keys()、Object.getOwnPropertyNames(),JSON.stringify()返回。
      // var a = 0;
      /**
       * 但是，它也不是私有属性，有一个Object.getOwnPropertySymbols()方法，可以获取指定对象的所有Symbol属性名。
       * 该方法返回一个数组，成员是当前对象的所有用作属性名的Symbol值。
       */
      var obj = {};
      var a = Symbol("a");
      var b = Symbol("b");

      obj[a] = "Hello";
      obj[b] = "World";

      var objectSymbols = Object.getOwnPropertySymbols(obj);

      objectSymbols;
      // [Symbol(a), Symbol(b)]
      /**
       * 上面代码是Object.getOwnPropertySymbols()方法的示例，可以获取所有 Symbol 属性名。
       * 下面是另一个例子，Object.getOwnPropertySymbols()方法与for...in循环、Object.getOwnPropertyNames方法进行对比的例子。
       */
    </script>
    <script>
      var obj = {};
      var foo = Symbol("foo");

      obj[foo] = "bar";

      for (var i in obj) {
        console.log(i); // 无输出
      }

      Object.getOwnPropertyNames(obj); // []
      Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
      //上面代码中，使用for...in循环和Object.getOwnPropertyNames()方法都得不到 Symbol 键名，需要使用Object.getOwnPropertySymbols()方法。
      //另一个新的 API，Reflect.ownKeys()方法可以返回所有类型的键名，包括常规键名和 Symbol 键名。
      var obj = {
        [Symbol("my_key")]: 1,
        enum: 2,
        nonEnum: 3,
      };

      var c = Reflect.ownKeys(obj);
      console.log(c)// ["enum", "nonEnum", Symbol(my_key)]
    </script>
    <script>
      // 由于以Symbol值作为键名，不会被常规方法遍历得到。我们可以利用这个特性，为对象定义一些非私有
      // 但是又希望只用于内部的方法。
      var size = Symbol('size');
      class Collection {
        constructor() {
          this[size] = 0;
        }
        add(item) {
          this[this[size]] = item;
          this[size]++;
        }
        static sizeOf(instance) {
          return instance[size];
        }
      }
      var x = new Collection();
      console.log('x是啥', x); // Collection {Symbol(size): 0}
      Collection.sizeOf(x); // 0
      x.add('foo');
      Collection.sizeOf(x); // 1
      Object.keys(x) // ['0']
      Object.getOwnPropertyNames(x) // ['0']
      Object.getOwnPropertySymbols(x) // [Symbol(size)]
      /**
       * 上面代码中，对象x的size属性是一个Symbol值，所以Object.keys(x)
       * Object.getOwnPropertyNames(x),都无法获取它，这就造成了一种非私有的内部方法的效果
      */
    </script>
  </body>
</html>
